package com.baoy.cloud.xxx.sso.shiro.filter;

import java.io.PrintWriter;
import java.util.concurrent.TimeUnit;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.alibaba.fastjson.JSON;
import com.baoy.cloud.xxx.common.Constant;
import com.baoy.cloud.xxx.common.JSONResult;
import com.baoy.cloud.xxx.sso.config.properties.SsoProperties;
import com.baoy.cloud.xxx.sso.shiro.session.SerializableUtils;
import com.baoy.cloud.xxx.sso.shiro.token.UsernamePasswordCaptchaToken;
import com.baoy.cloud.xxx.sso.utils.IpUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;


public class FormAuthenticationFilter extends
        org.apache.shiro.web.filter.authc.FormAuthenticationFilter {

    @Autowired
    SsoProperties ssoProperties;

    @Autowired
    RedisTemplate redisTemplate;

    String captchaParam = Constant.CAPTCHA;

    protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) {
        String username = getUsername(request);
        String password = getPassword(request);
        boolean rememberMe = isRememberMe(request);
        String host = IpUtils.getIpAddress((HttpServletRequest) request);
        String captcha = WebUtils.getCleanParam(request, captchaParam);
        return new UsernamePasswordCaptchaToken(username, password.toCharArray(), rememberMe, host,
                captcha);
    }

    /**
     * 验证码校验, 调试阶段注释代码
     */
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response)
            throws Exception {
        // HttpServletRequest req = WebUtils.toHttp(request);
        // String sessionCaptcha = (String)
        // org.springframework.web.util.WebUtils.getSessionAttribute(httpServletRequest,
        // captchaParam);
        // String requestCaptcha =
        // org.apache.shiro.web.util.WebUtils.getCleanParam(request, captchaParam);
        // if (!StringUtils.endsWithIgnoreCase(sessionCaptcha, requestCaptcha)) {
        // httpServletRequest.setAttribute(DEFAULT_ERROR_KEY_ATTRIBUTE_NAME, "验证码错误!");
        // return true;
        // }
        return super.onAccessDenied(request, response);
    }

    @Override
    protected boolean onLoginSuccess(AuthenticationToken token, Subject subject,
            ServletRequest request, ServletResponse response) throws Exception {
        HttpServletRequest req = WebUtils.toHttp(request);
        HttpServletResponse resp = WebUtils.toHttp(response);
        if (!"XMLHttpRequest".equalsIgnoreCase(req.getHeader("X-Requested-With"))) {
            issueSuccessRedirect(request, response);
        } else {
            resp.setCharacterEncoding("UTF-8");
            PrintWriter out = resp.getWriter();
            out.write(JSON.toJSONString(JSONResult.writeData("/index")));
            out.flush();
            out.close();
        }
        return false;
    }

    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response,
            Object mappedValue) {
        // 客户端校验
        if (StringUtils.equals(ssoProperties.getType(), Constant.CLIENT)) {
            Session session = getSubject(request, response).getSession();
            String sessionId = session.getId().toString();
            String sessionJson = (String) redisTemplate.opsForValue()
                    .get(Constant.getShiroSessionId(sessionId.toString()));
            if (StringUtils.isNotBlank(sessionJson)) {
                // 更新code有效期
                redisTemplate.opsForValue().set(Constant.getShiroSessionId(sessionId),
                        SerializableUtils.serialize(session), session.getTimeout(),
                        TimeUnit.MILLISECONDS);
                return true;
            }
            return false;
        }
        return super.isAccessAllowed(request, response, mappedValue);
    }

}